package com.huiyeji.dynamic.core;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.huiyeji.dynamic.core.annotations.DynamicBean;
import com.huiyeji.dynamic.core.annotations.DynamicMethod;
import com.huiyeji.dynamic.core.annotations.Private;
import com.huiyeji.sort.SortedComparator;

import java.util.*;

/**
 * @author Huiyeji
 */
@DynamicBean("monitor")
public class DynamicMonitor {

    private final Map<String, Object> monitorData = new TreeMap<String, Object>(new SortedComparator<String>());

    private final DynamicContext context;

    public DynamicMonitor(DynamicContext context) {
        this.context = context;
    }

    @DynamicMethod("any")
    public Map<String, Object> _doAny(Object id){
        int position = this.context.getPointer().getCurrentPosition();
        Map<String, Object> snapshot = new HashMap<String, Object>();
        Map<String, Object> contextData = context.getContextData();
        Map<String, Object> contextObjects = new HashMap<String, Object>();
        for (Map.Entry<String, Object> entry : contextData.entrySet()) {
            prepareContextObjectMap(contextObjects,entry.getKey(), entry.getValue());
        }
        snapshot.put("contextObjects",contextObjects);
        Map<String, Object> dynamicObjects = new HashMap<String, Object>();
        for (DynamicObject dynamicObject : context.getFactory().getDynamicObjectMap().values()) {
            prepareDynamicObjectMap(dynamicObjects, dynamicObject);
        }
        snapshot.put("dynamicObjects",dynamicObjects);
        monitorData.put("Monitor-Context-Snapshot-"+UUID.randomUUID().toString().replace("-","")+"-P" + position + (id == null ? "" : "-["+id+"]") , snapshot);
        return snapshot;
    }

    @DynamicMethod("any")
    public Map<String, Object> _doAny(){
        return _doAny(null);
    }

    @DynamicMethod("one")
    public Map<String, Object> _doOne(String objectName){
        if (objectName == null || objectName.isEmpty()){
            throw new RuntimeException("Monitor Error : objectName is empty !");
        }
        int position = context.getPointer().getCurrentPosition();
        Map<String, Object> snapshot = new HashMap<String, Object>();
        Object object = context.getObject(objectName);
        if (object != null){
            snapshot.put("object", toJson(object));
            snapshot.put("type",object.getClass().getName());
            if (context.getFactory().containsDynamicObject(objectName)){
                snapshot.put("dynamic", true);
            }
        } else {
            DynamicObject dynamicObject = context.getFactory().getDynamicObject(objectName);
            if (dynamicObject != null){
                snapshot.put("object",toJson(dynamicObject.getObject()));
                snapshot.put("type",dynamicObject.getObject().getClass().getName());
                snapshot.put("dynamic",true);
            }
        }
        monitorData.put("Monitor-Object-Snapshot-"+ UUID.randomUUID().toString().replace("-","")+"-P" + position + "-[" + objectName + "]", snapshot);
        return snapshot;
    }

    private void prepareDynamicObjectMap(Map<String, Object> dynamicObjects, DynamicObject dynamicObject){
        Map<String, Object> dynamicObjectMap = new HashMap<String, Object>();
        dynamicObjectMap.put("type",dynamicObject.getObject() == null ? null : dynamicObject.getObject().getClass().getName());
        dynamicObjectMap.put("object",toJson(dynamicObject.getObject()));
        dynamicObjects.put(dynamicObject.getDynamicObjectName(),dynamicObjectMap);
    }

    private void prepareContextObjectMap(Map<String, Object> contextObjects, String objectName , Object object){
        Map<String, Object> contextObjectMap = new HashMap<String, Object>();
        contextObjectMap.put("object",toJson(object));
        contextObjectMap.put("type", object == null ? null : object.getClass().getName());
        contextObjects.put(objectName,contextObjectMap);
    }

    private Object toJson(Object object){
        if (object == null){
            return null;
        }
        if (object instanceof String){
            return object;
        }
        if (object instanceof Number){
            return object;
        }
        String jsonString;
        try {
            jsonString = JSON.toJSONString(object);
        } catch (Throwable throwable){
            jsonString = object.toString();
        }
        return jsonString;
    }

    @Private
    protected Map<String, Object> getMonitorData() {
        string2Object(monitorData);
        return monitorData;
    }

    private void string2Object(Map<String,Object> map){
        if (map.size() > 0){
            for (Map.Entry<String, Object> entry : map.entrySet()) {
                if (entry.getValue() instanceof String){
                    try {
                        Object object = JSON.parse(entry.getValue().toString());
                        entry.setValue(object);
                    } catch (Throwable throwable){
                        //ignore
                    }
                } else if (entry.getValue() instanceof Map) {
                    string2Object((Map<String, Object>) entry.getValue());
                }
            }
        }
    }

    @Private
    protected void tempClear(){
        monitorData.clear();
    }
}
